﻿
Imports std

Public Class url
    Public enc As Text.Encoding = Nothing

    Private _host As String = Nothing
    Public protocol As String = Nothing
    Public port As String = "80"
    Public user As String = Nothing
    Public password As String = Nothing
    Private _path As String = Nothing
    Private _queryString As String = Nothing
    Public query As map(Of String, String) = Nothing
    Private _pathquery As String = Nothing
    Private _full As String = Nothing
    Public position As String = Nothing
    Public unknown As String = Nothing

    Public Function queryInt64(ByVal name As String, ByRef rtn As Int64) As Boolean
        Dim it As map(Of String, String).iterator = Nothing
        it = query.find(name)
        If it = query.end() OrElse Not convertor.toint64((+it).second, rtn) Then
            Return False
        Else
            Return True
        End If
    End Function

    Public Function queryInt64(ByVal name As String) As Int64
        Dim rtn As Int64
        If queryInt64(name, rtn) Then
            Return rtn
        Else
            Return npos
        End If
    End Function

    Public Function queryInt32(ByVal name As String, ByRef rtn As Int32) As Boolean
        Dim it As map(Of String, String).iterator = Nothing
        it = query.find(name)
        If it = query.end() OrElse Not convertor.toint32((+it).second, rtn) Then
            Return False
        Else
            Return True
        End If
    End Function

    Public Function queryInt32(ByVal name As String) As Int32
        Dim rtn As Int32
        If queryInt32(name, rtn) Then
            Return rtn
        Else
            Return npos
        End If
    End Function

    Public Function queryBoolean(ByVal name As String, ByRef rtn As Boolean) As Boolean
        Dim it As map(Of String, String).iterator = Nothing
        it = query.find(name)
        If it = query.end() Then
            Return False
        Else
            rtn = strsame((+it).second, "true", False) OrElse Not strsame((+it).second, "0", False)
            Return True
        End If
    End Function

    Public Function queryBoolean(ByVal name As String) As Boolean
        Dim rtn As Boolean
        If queryBoolean(name, rtn) Then
            Return rtn
        Else
            Return False
        End If
    End Function

    Public Function queryExist(ByVal name As String) As Boolean
        Return query.find(name) <> query.end()
    End Function

    Public Property host() As String
        Get
            Return _host
        End Get
        Private Set(ByVal value As String)
            copy(_host, value)
            If Not isemptystring(_host) Then
                Dim index As Int32
                index = _host.IndexOf(network.portMark)
                If index <> npos Then
#If RETIRED Then
                    assert(convertor.toint32(strmid(_host, index + 1), port) _
                           , "get invalid user host name " + _host)
#End If
                    port = strmid(_host, index + 1)
                    _host = strleft(host, index)
                End If
            End If
        End Set
    End Property

    Public Property queryString() As String
        Get
            Return _queryString
        End Get
        Private Set(ByVal value As String)
            copy(_queryString, value)
            query.clear()
            If Not isemptystring(_queryString) Then
                Dim queries As vector(Of pair(Of String, String)) = Nothing
                If Not urlUtils.parseQueryString(_queryString, queries, False, enc) Then
                    raiseError("get invalid url, " + _full, errorHandle.errorType.warning)
                ElseIf Not queries Is Nothing Then
                    Dim i As Int64
                    For i = 0 To queries.size() - 1
                        If query.find(queries(i).first) = query.end() Then
                            query(queries(i).first) = queries(i).second
                        Else
                            query(queries(i).first) += character.blank + queries(i).second
                        End If
                    Next
                End If
            End If
        End Set
    End Property

    Public Property pathquery() As String
        Get
            Return _pathquery
        End Get
        Private Set(ByVal value As String)
            copy(_pathquery, value)
            If isemptystring(_pathquery) Then
                _pathquery = network.pathSeperator
            End If
            If _pathquery(0) <> network.pathSeperator Then
                _pathquery = network.pathSeperator + _pathquery
            End If

            Dim index As Int32
            index = _pathquery.IndexOf(network.questionMark)
            If index <> npos Then
                path = strleft(_pathquery, index)
                queryString = strmid(_pathquery, index)
            Else
                path = _pathquery
                queryString = emptyString
            End If
        End Set
    End Property

    Public Property path() As String
        Get
            Return _path
        End Get
        Private Set(ByVal value As String)
            copy(_path, value)
            If isemptystring(_path) Then
                _path = network.pathSeperator
            End If
            If _path(0) <> network.pathSeperator Then
                _path = network.pathSeperator + _path
            End If
        End Set
    End Property

    'to the user of this class, can only set full, the class will handle path/pathquery/querystring/query
    Public Property full() As String
        Get
            Return _full
        End Get
        Set(ByVal value As String)
            copy(_full, value)
            Dim path As String = Nothing
            Dim querystring As String = Nothing
            urlUtils.splitUrl(value, protocol, user, password, host, port, path, querystring, position, unknown)
            'call only pathquery, pathquery will call path and querystring
            Me.pathquery = path + ifoper(isemptystring(querystring), Nothing, network.questionMark + querystring)
        End Set
    End Property

    Public Overrides Function ToString() As String
        Return full()
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return full().GetHashCode()
    End Function

    Public Sub New()
        query = New map(Of String, String)()
    End Sub
End Class
